package mysgoog.board;

import java.util.*;

import mysgoog.brown.*;
import mysgoog.gtp.*;

/**
 * 
 * @author Qing
 */
public class DragonBoard extends Board {

	public DragonBoard(int len) {
		super(len);
		dragonAt = new Dragon[BOARD_ELEMNUM];
		for (int pos = 0; pos < BOARD_ELEMNUM; pos++)
			dragonAt[pos] = null;
		territoryAt = new Dragon[BOARD_ELEMNUM];
		for (int pos = 0; pos < BOARD_ELEMNUM; pos++)
			territoryAt[pos] = null;
	}

	protected LinkedList<Dragon> black_dragons = new LinkedList<Dragon>(),
			white_dragons = new LinkedList<Dragon>();
	protected Dragon[] dragonAt;
	protected Dragon[] territoryAt;
	public LinkedList<Integer> white_conn = new LinkedList<Integer>(),
			black_conn = new LinkedList<Integer>();

	public DragonBoard copy() {
		// TODO
		Lib.assertNotReached();
		DragonBoard res = new DragonBoard(BOARD_LENGTH);
		res = new DragonBoard(BOARD_LENGTH);
		res.board = board.clone();
		res.history = new LinkedList<HistoryEvent>(history);
		res.white_worms = new LinkedList<Worm>(white_worms);
		res.black_worms = new LinkedList<Worm>(black_worms);
		res.wormAt = wormAt.clone();
		res.turn = turn;
		res.tsn = tsn;
		res.black_dragons = new LinkedList<Dragon>(black_dragons);
		res.white_dragons = new LinkedList<Dragon>(white_dragons);
		res.dragonAt = dragonAt.clone();
		res.territoryAt = territoryAt.clone();
		return res;
	}

	private void addDragon(Color color, Dragon dragon) {
		getDragons(color).add(dragon);
		for (Worm w : dragon)
			for (int pos : w)
				dragonAt[pos] = dragon;

		// for (int pos : dragon.getStones())

		// for (int pos : dragon.getTerritories())
		// territoryAt[pos] = dragon;
	}

	private void removeDragon(Color color, Dragon dragon) {
		getDragons(color).remove(dragon);
		for (Worm w : dragon)
			for (int pos : w)
				dragonAt[pos] = null;

		// for (int pos : dragon.getStones())

		// for (int pos : dragon.getTerritories())
		// territoryAt[pos] = null;
	}

	public LinkedList<Dragon> getDragons(Color color) {
		if (color == Color.BLACK)
			return black_dragons;
		else
			return white_dragons;
	}

	public Dragon dragonAt(int pos) {
		return dragonAt[pos];
	}

	public Dragon territoryAt(int pos) {
		return territoryAt[pos];
	}

	@Override
	public void play(Color c, int pos) {

		super.play(c, pos);

		reCalcDragon();

		for (Color color : Color.getColors())
			for (Dragon d : getDragons(color)) {
				for (int p : d.getTerritories())
					territoryAt[p] = d;
			}
	}

	public void undo() {
		super.undo();
		reCalcDragon();
		for (Color color : Color.getColors())
			for (Dragon d : getDragons(color)) {
				for (int p : d.getTerritories())
					territoryAt[p] = d;
			}
	}

	private void reCalcDragon() {

		white_conn.clear();
		black_conn.clear();

		Color toPlay;
		if (history.size() > 0)
			toPlay = history.getLast().player.complement();
		else
			toPlay = Color.BLACK;

		for (int i = 0; i < BOARD_ELEMNUM; i++) {
			dragonAt[i] = null;
			territoryAt[i] = null;
		}

		for (Color color : Color.getColors()) {
			if (color == Color.BLACK)
				black_dragons.clear();
			if (color == Color.WHITE)
				white_dragons.clear();

			for (Worm worm : getWorms(color)) {
				Dragon d = new Dragon(this, color);

				d.add(worm);

				addDragon(color, d);

			}

			for (Worm worm1 : getWorms(color))
				for (Worm worm2 : getWorms(color)) {

					if (worm1 != worm2
							&& dragonAt(worm1.getOne()) != dragonAt(worm2
									.getOne())
							&& ableToConn(worm1, worm2, color.complement(),
									toPlay)) {
						Dragon dragon1 = dragonAt(worm1.getOne());
						Dragon dragon2 = dragonAt(worm2.getOne());

						Dragon newDragon = new Dragon(this, color);
						newDragon.addAll(dragon1);
						newDragon.addAll(dragon2);
						removeDragon(color, dragon1);
						removeDragon(color, dragon2);
						addDragon(color, newDragon);
					}
				}

		}
	}

	private boolean ableToConn(Worm worm1, Worm worm2, Color hostile,
			Color toPlay) {
		PosSet lib1 = worm1.getLibs();
		PosSet lib2 = worm2.getLibs();
		PosSet inter = lib1.intersection(lib2);
		int interLibs = inter.size();

		int danger = 0;
		int self = 0;

		if (interLibs > 1)
			return true;
		else if (interLibs == 1 && (lib1.size() + lib2.size() > 2)) {
			int pos = inter.getOne();

			ArrayList<Integer> neis = getAdjacent(pos);
			for (int k = 0; k < neis.size(); k++)
				if (getStone(neis.get(k)) == hostile)
					danger++;
				else if (getStone(neis.get(k)) == hostile.complement())
					self++;

			if (danger == 0) {
				//if (isEdge(pos))
					//if (hostile == Color.WHITE)
						//black_conn.add(pos);
					//else
						//white_conn.add(pos);
				return true;
			} else if (danger == 2) {
				if (hostile == Color.WHITE)
					black_conn.add(pos);
				else
					white_conn.add(pos);
				return false;
			} else {
				if (isEdge(pos) || self == 3)
					if (hostile == Color.WHITE)
						black_conn.add(pos);
					else
						white_conn.add(pos);

				if (toPlay != hostile)
					return true;
			}

		} else {
			for (int p1 : lib1) {
				ArrayList<Integer> nei1 = getAdjacent(p1);

				for (int k = 0; k < nei1.size(); k++) {

					int p2 = nei1.get(k);
					if (getStone(p2) == Color.EMPTY && lib2.contains(p2)) {
						danger = 0;
						int danger2 = 0;
						ArrayList<Integer> nei2 = getAdjacent(p2);
						for (int e2 = 0; e2 < nei2.size(); e2++) {
							if (getStone(nei2.get(e2)) == hostile)
								danger2++;
						}
						for (int e1 = 0; e1 < nei1.size(); e1++) {
							if (getStone(nei1.get(e1)) == hostile)
								danger++;
						}

						if ((danger + danger2) == 1 && isEdge(p1) && isEdge(p2)) {
							if (hostile == Color.WHITE)
								black_conn.add(danger == 1 ? p1 : p2);
							else
								white_conn.add(danger == 1 ? p1 : p2);
						}

						if ((danger + danger2) < 2)
							return true;

					}
				}
			}
		}
		return false;
	}
}
